// Copyright (c) 2022 Presto Labs Pte. Ltd.
// Author: hyuan

#include "coin2/exchange/mexc/api_util/auth_key.h"

#include <fmt/format.h>
#include <nlohmann/json.hpp>
#include "md5.h"

#include "coin2/base/time.h"
#include "coin2/base/string_util.h"

auto MexcBaseAuth::GetHeaderSet(const std::string& query_str) -> const HeaderSet& {
  CHECK_THROW(!header_set_.empty()) << "Header set is empty";
  std::string timestamp = std::to_string(GetCurrentTimestamp() / 1000000LL);
  std::string raw_str = access_key_ + timestamp + query_str;
  header_set_[0].second = access_key_;
  header_set_[1].second = timestamp;
  header_set_[2].second =
      ApiSignatureUtil::GetSignatureByHexHmacSHA256(raw_str, secret_key_);
  return header_set_;
}

auto MexcBaseAuth::GetHeaderSetV3() -> const HeaderSet& {
  CHECK_THROW(!header_set_.empty()) << "Header set is empty";
  header_set_v3_[0].second = access_key_;
  return header_set_v3_;
}

AsioHttpContext* MexcRestAuth::CreateRequestByGetWithSignature(
    const std::string& address,
    UrlParamsBuilder* builder) {
  std::string query_string = builder->ComputeQueryString();
  std::string target = address;
  
  if (StringStartsWith(address, "/api/v3")){
    std::string signa = BuildSignaturePath(key_.secret_key(), query_string);
    if (!query_string.empty()) {
      target += "?" + query_string + "&" + signa;
    } else {
      target += "?" + signa;
    }
    auto ahc = AsioHttpContext::NewGet("api.mexc.com", port_, bind_ip_, target, GetHeaderSetV3());
    ahc->keep_user_agent = true;
    return ahc;
  }else{
    if (!query_string.empty()) {
      target += "?" + query_string;
    }
    auto ahc = AsioHttpContext::NewGet(host_, port_, bind_ip_, target,
      GetHeaderSet(GetQueryString(query_string)));
    ahc->keep_user_agent = true;
    return ahc;
  }
}

AsioHttpContext* MexcRestAuth::CreateRequestByPostWithSignature(
    const std::string& address,
    UrlParamsBuilder* builder) {
  std::string query_string = builder->ComputeQueryString();
  std::string post_body = builder->ComputePostBody();
  std::string target = address;
  if (!query_string.empty()) {
    target += "?" + query_string;
  }
  auto ahc = AsioHttpContext::NewPost(host_, port_, bind_ip_, target,
      GetHeaderSet(post_body), post_body);
  ahc->keep_user_agent = true;

  return ahc;
}

AsioHttpContext* MexcRestAuth::CreateRequestByDeleteWithSignature(
    const std::string& address,
    UrlParamsBuilder* builder) {
  std::string query_string = builder->ComputeQueryString();
  std::string post_body = builder->ComputePostBody();
  std::string target = address;
  if (!query_string.empty()) {
    target += "?" + query_string;
  }
  return AsioHttpContext::NewDelete(host_, port_, bind_ip_, target,
      GetHeaderSet(GetQueryString(query_string)), "");
}

const std::string MexcWsAuth::CreateSignature(
    const std::string& op,
    const std::string& timestamp) const {
  std::map<std::string, std::string> m;
  m.insert(std::make_pair("api_key", key_.access_key()));
  m.insert(std::make_pair("op", op));
  m.insert(std::make_pair("req_time", timestamp));
  std::string raw_str = "";
  for (auto x: m)
  {
    raw_str += x.first + "=" + x.second + "&";
  }
  raw_str += "api_secret=" + key_.secret_key();
  MD5 md5 = MD5(raw_str);
  return md5.hexdigest();
}
